#include "functions.h"
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
NUMBER_STACK NS;
OPERATOR_STACK OS;
void evaluate_expression()
{
    FILE *fp = fopen("in.txt", "r+");
    int c, excess = 0;
    char op;
    while ((c = fgetc(fp)) != '\n')
    {
        switch (c)
        {
            case '(':
                excess += 10;
                break;
            case ')':
                excess -= 10;
                break;
            case '#':
                if (OS.first == NULL)
                    push_operator(c, 0 + excess, &OS);
                else
                {
                    while (OS.last -> priority != 0 + excess)
                    {
                        op = pop_operator(&OS);
                        do_operation(op);
                        pop_number(&NS);
                    }
                    push_operator(c, 0 + excess, &OS);
                }
                break;
            case '+':
                if (1 + excess > OS.last -> priority)
                    push_operator(c, 1 + excess, &OS);
                else
                {
                    while (1 + excess <= OS.last -> priority)
                    {
                        op = pop_operator(&OS);
                        do_operation(op);
                        pop_number(&NS);
                    }
                    push_operator(c, 1 + excess, &OS);
                }
                break;
            case '-':
                if (1 + excess > OS.last -> priority)
                    push_operator(c, 1 + excess, &OS);
                else
                {
                    while (1 + excess <= OS.last -> priority)
                    {
                        op = pop_operator(&OS);
                        do_operation(op);
                        pop_number(&NS);
                    }
                    push_operator(c, 1 + excess, &OS);
                }
                break;
            case '*':
                if (2 + excess > OS.last -> priority)
                    push_operator(c, 2 + excess, &OS);
                else
                {
                    while (2 + excess <= OS.last -> priority)
                    {
                        op = pop_operator(&OS);
                        do_operation(op);
                        pop_number(&NS);
                    }
                    push_operator(c, 2 + excess, &OS);
                }
                break;
            case '/':
                if (2 + excess > OS.last -> priority)
                    push_operator(c, 2 + excess, &OS);
                else
                {
                    while (2 + excess <= OS.last -> priority)
                    {
                        op = pop_operator(&OS);
                        do_operation(op);
                        pop_number(&NS);
                    }
                    push_operator(c, 2 + excess, &OS);
                }
                break;
            default:
                push_number(c - '0', &NS);
        }
    }
    print_number_stack(NS);
}
void push_number(int x, NUMBER_STACK *NS)
{
    Nnode *tmp;
    tmp = (Nnode *)malloc(sizeof(Nnode));
    tmp -> number = x;
    tmp -> prev = NULL;
    tmp -> next = NULL;
    if(NS -> last != NULL)
    {
        tmp -> prev = NS -> last;
        NS -> last -> next = tmp;
        NS -> last = tmp;
    }
    else
    {
        NS -> first = NS -> last = tmp;
    }
}
void push_operator(char x, int p, OPERATOR_STACK *OS)
{
    Onode *tmp;
    tmp = (Onode *)malloc(sizeof(Onode));
    tmp -> symbol = x;
    tmp -> priority = p;
    tmp -> prev = NULL;
    tmp -> next = NULL;
    if(OS -> last != NULL)
    {
        tmp -> prev = OS -> last;
        OS -> last -> next = tmp;
        OS -> last = tmp;
    }
    else
    {
        OS -> first = OS -> last = tmp;
    }
}
void print_number_stack(NUMBER_STACK NS)
{
    FILE *fp = fopen("out.txt", "r+");
    Nnode *tmp = NS.first;
    if(tmp == NULL)
        printf("Stack is empty.");
    else
        for(; tmp != NULL; tmp = tmp -> next)
            fprintf(fp, "%f", tmp -> number);
    fclose(fp);
}
void print_operator_stack(OPERATOR_STACK OS)
{
    Onode *tmp = OS.first;
    if(tmp == NULL)
        printf("Stack is empty.");
    else
        for(; tmp != NULL; tmp = tmp -> next)
            printf("%c\t%d\n", tmp -> symbol, tmp -> priority);
}
void do_operation(char op)
{
    switch (op)
    {
        case '+':
            NS.last -> prev -> number += NS.last -> number;
            break;
        case '-':
            NS.last -> prev -> number -= NS.last -> number;
            break;
        case '*':
            NS.last -> prev -> number *= NS.last -> number;
            break;
        case '/':
            NS.last -> prev -> number /= NS.last -> number;
            break;
        default:
            printf("Unknown operator.");
    }
}
int pop_number(NUMBER_STACK *NS)
{
    int info = NS -> last -> number;
    Nnode *tmp = NS -> last;
    tmp -> prev -> next = NULL;
    NS -> last = tmp -> prev;
    free(tmp);
    return info;
}
char pop_operator(OPERATOR_STACK *OS)
{
    char info = OS -> last -> symbol;
    Onode *tmp = OS -> last;
    tmp -> prev -> next = NULL;
    OS -> last = tmp -> prev;
    free(tmp);
    return info;
}

